home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games: Greatest Hits 1996 / Amiga Games: Greatest Hits 1996.iso / spiele / publicdomain / scott / source / source.lha / SCOTT.C < prev    next >
C/C++ Source or Header  |  1996-07-30  |  26KB  |  1,431 lines

  1. /*
  2.  *  ScottFree Revision 1.14b
  3.  *
  4.  *
  5.  *  This program is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU General Public License
  7.  *  as published by the Free Software Foundation; either version
  8.  *  2 of the License, or (at your option) any later version.
  9.  *
  10.  *
  11.  *  You must have an ANSI C compiler to build this program.
  12.  *
  13.  *  ===================================================================
  14.  *
  15.  *  Version History AMIGA:
  16.  *  Ver ,     Date,         Author, Comment
  17.  *  -------------------------------------------------------------------
  18.  *  1.0 , 28/07/96, Andreas Aumayr, First public release
  19.  *  ___________________________________________________________________
  20.  */
  21.  
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <stdarg.h>
  28. #include <time.h>
  29. #include "Scott.h"
  30. #include "ansi.c"
  31. #include "amiga.c"
  32.  
  33.  
  34. static int strnicmp(char *a,char *b, int n)
  35. {
  36.     while(*a&&n>0)
  37.     {
  38.         char c=*a;
  39.         char d=*b;
  40.         if(islower(c))
  41.             c=toupper(c);
  42.         if(islower(d))
  43.             d=toupper(d);
  44.         if(c<d)
  45.             return(-1);
  46.         if(c>d)
  47.             return(1);
  48.         a++;
  49.         b++;
  50.         n--;
  51.         if(n==0)
  52.             return(0);
  53.     }
  54.     if(*b)
  55.         return(1);
  56.     return(0);
  57. }
  58.  
  59. void Fatal(char *x)
  60. {
  61.     sprintf(str_buf,"%s.\n\n- Press ENTER to exit -",x);
  62.     WriteCON(str_buf);
  63.     WaitForChar(CON_handle,30000000);
  64.     close_all();
  65.     exit(1);
  66. }
  67.  
  68. void Aborted()
  69. {
  70.     Fatal("User exit");
  71. }
  72.  
  73. void ClearScreen(void)
  74. {
  75.     clrscr();
  76. }
  77.  
  78. void *MemAlloc(int size)
  79. {
  80.     void *t=(void *)malloc(size);
  81.     if(t==NULL)
  82.         Fatal("Out of memory");
  83.     return(t);
  84. }
  85.  
  86. int RandomPercent(int n)
  87. {
  88.     unsigned int rv=rand()<<6;
  89.     rv=rv%100;
  90.     if(rv<n)
  91.         return(1);
  92.     return(0);
  93. }
  94.  
  95. int CountCarried()
  96. {
  97.     int ct=0;
  98.     int n=0;
  99.     while(ct<=GameHeader.NumItems)
  100.     {
  101.         if(Items[ct].Location==CARRIED)
  102.             n++;
  103.         ct++;
  104.     }
  105.     return(n);
  106. }
  107.  
  108. char *MapSynonym(char *word)
  109. {
  110.     int n=1;
  111.     char *tp;
  112.     static char lastword[16];   /* Last non synonym */
  113.     while(n<=GameHeader.NumWords)
  114.     {
  115.         tp=Nouns[n];
  116.         if(*tp=='*')
  117.             tp++;
  118.         else
  119.             strcpy(lastword,tp);
  120.         if(strnicmp(word,tp,GameHeader.WordLength)==0)
  121.             return(lastword);
  122.         n++;
  123.     }
  124.     return(NULL);
  125. }
  126.  
  127. int MatchUpItem(char *text, int loc)
  128. {
  129.     char *word=MapSynonym(text);
  130.     int ct=0;
  131.     
  132.     if(word==NULL)
  133.         word=text;
  134.     
  135.     while(ct<=GameHeader.NumItems)
  136.     {
  137.         if(Items[ct].AutoGet && Items[ct].Location==loc &&
  138.             strnicmp(Items[ct].AutoGet,word,GameHeader.WordLength)==0)
  139.             return(ct);
  140.         ct++;
  141.     }
  142.     return(-1);
  143. }
  144.  
  145. char *ReadString(FILE *f)
  146. {
  147.     char tmp[1024];
  148.     char *t;
  149.     int c,nc;
  150.     int ct=0;
  151. oops:   do
  152.     {
  153.         c=fgetc(f);
  154.     }
  155.     while(c!=EOF && isspace(c));
  156.     if(c!='"')
  157.     {
  158.         Fatal("Initial quote expected");
  159.     }
  160.     do
  161.     {
  162.         c=fgetc(f);
  163.         if(c==EOF)
  164.             Fatal("EOF in string");
  165.         if(c=='"')
  166.         {
  167.             nc=fgetc(f);
  168.             if(nc!='"')
  169.             {
  170.                 ungetc(nc,f);
  171.                 break;
  172.             }
  173.         }
  174.         if(c==0x60) 
  175.             c='"'; /* pdd */
  176.         tmp[ct++]=c;
  177.     }
  178.     while(1);
  179.     tmp[ct]=0;
  180.     t=MemAlloc(ct+1);
  181.     memcpy(t,tmp,ct+1);
  182.     return(t);
  183. }
  184.  
  185. void Look()
  186. {
  187.     static char *ExitNames[6]=
  188.     {
  189.         "North","South","East","West","Up","Down"
  190.     };
  191.     Room *r;
  192.     int ct,f;
  193.     int pos;
  194.  
  195.     CON_handle = env_hdl;
  196.     clrscr();
  197.  
  198.     if((BitFlags&(1L<<DARKBIT)) && Items[LIGHT_SOURCE].Location!= CARRIED
  199.             && Items[LIGHT_SOURCE].Location!= MyLoc)
  200.     {
  201.         if(Options&YOUARE)
  202.             WriteCON("You can't see. It is too dark!\n");
  203.         else
  204.             WriteCON("I can't see. It is too dark!\n");
  205.         if (Options & TRS80_STYLE)
  206.             WriteCON(TRS80_LINE);
  207.         CON_handle = act_hdl;
  208.         return;
  209.     }
  210.     r=&Rooms[MyLoc];
  211.     if(*r->Text=='*') {
  212.         sprintf(str_buf,"%s\n",r->Text+1);
  213.         WriteCON(str_buf);
  214.     }
  215.     else
  216.     {
  217.         if(Options&YOUARE) {
  218.             sprintf(str_buf,"You are %s\n",r->Text);
  219.             WriteCON(str_buf);
  220.         }
  221.         else {
  222.             sprintf(str_buf,"I'm in a %s\n",r->Text);
  223.             WriteCON(str_buf);
  224.         }
  225.     }
  226.     ct=0;
  227.     f=0;
  228.     WriteCON("\nObvious exits: ");
  229.     while(ct<6)
  230.     {
  231.         if(r->Exits[ct]!=0)
  232.         {
  233.             if(f==0)
  234.                 f=1;
  235.             else
  236.                 WriteCON(", ");
  237.             sprintf(str_buf,"%s",ExitNames[ct]);
  238.             WriteCON(str_buf);
  239.         }
  240.         ct++;
  241.     }
  242.     if(f==0)
  243.         WriteCON("none");
  244.     WriteCON(".\n");
  245.     ct=0;
  246.     f=0;
  247.     pos=0;
  248.     while(ct<=GameHeader.NumItems)
  249.     {
  250.         if(Items[ct].Location==MyLoc)
  251.         {
  252.             if(f==0)
  253.             {
  254.                 if(Options&YOUARE)
  255.                     WriteCON("\nYou can also see: ");
  256.                 else
  257.                     WriteCON("\nI can also see: ");
  258.                 pos=16;
  259.                 f++;
  260.             }
  261.             else if (!(Options & TRS80_STYLE))
  262.             {
  263.                 WriteCON(" - ");
  264.                 pos+=3;
  265.             }
  266.             if(pos+strlen(Items[ct].Text)>(Width-10))
  267.             {
  268.                 pos=0;
  269.                 WriteCON("\n");
  270.             }
  271.             sprintf(str_buf,"%s",Items[ct].Text);
  272.             WriteCON(str_buf);
  273.             pos += strlen(Items[ct].Text);
  274.             if (Options & TRS80_STYLE)
  275.             {
  276.                 WriteCON(". ");
  277.                 pos+=2;
  278.             }
  279.         }
  280.         ct++;
  281.     }
  282.     if (Options & TRS80_STYLE) {
  283.         WriteCON("\n");
  284.         WriteCON(TRS80_LINE);
  285.     }
  286.     CON_handle = act_hdl;
  287. }
  288.  
  289. void LoadDatabase(FILE *f, int loud)
  290. {
  291.     int ni,na,nw,nr,mc,pr,tr,wl,lt,mn,trm;
  292.     int ct;
  293.     short lo;
  294.     Action *ap;
  295.     Room *rp;
  296.     Item *ip;
  297. /* Load the header */
  298.  
  299.     if(fscanf(f,"%*d %d %d %d %d %d %d %d %d %d %d %d",
  300.         &ni,&na,&nw,&nr,&mc,&pr,&tr,&wl,<,&mn,&trm,&ct)<10)
  301.         Fatal("Invalid database(bad header)");
  302.     GameHeader.NumItems=ni;
  303.     Items=(Item *)MemAlloc(sizeof(Item)*(ni+1));
  304.     GameHeader.NumActions=na;
  305.     Actions=(Action *)MemAlloc(sizeof(Action)*(na+1));
  306.     GameHeader.NumWords=nw;
  307.     GameHeader.WordLength=wl;
  308.     Verbs=(char **)MemAlloc(sizeof(char *)*(nw+1));
  309.     Nouns=(char **)MemAlloc(sizeof(char *)*(nw+1));
  310.     GameHeader.NumRooms=nr;
  311.     Rooms=(Room *)MemAlloc(sizeof(Room)*(nr+1));
  312.     GameHeader.MaxCarry=mc;
  313.     GameHeader.PlayerRoom=pr;
  314.     GameHeader.Treasures=tr;
  315.     GameHeader.LightTime=lt;
  316.     LightRefill=lt;
  317.     GameHeader.NumMessages=mn;
  318.     Messages=(char **)MemAlloc(sizeof(char *)*(mn+1));
  319.     GameHeader.TreasureRoom=trm;
  320.  
  321. /* Load the actions */
  322.  
  323.     ct=0;
  324.     ap=Actions;
  325.     if(loud)
  326.         printf("Reading %d actions.\n",na);
  327.     while(ct<na+1)
  328.     {
  329.         if(fscanf(f,"%hd %hd %hd %hd %hd %hd %hd %hd",
  330.             &ap->Vocab,
  331.             &ap->Condition[0],
  332.             &ap->Condition[1],
  333.             &ap->Condition[2],
  334.             &ap->Condition[3],
  335.             &ap->Condition[4],
  336.             &ap->Action[0],
  337.             &ap->Action[1])!=8)
  338.         {
  339.             printf("Bad action line (%d)\n",ct);
  340.             exit(1);
  341.         }
  342.         ap++;
  343.         ct++;
  344.     }
  345.     ct=0;
  346.     if(loud)
  347.         printf("Reading %d word pairs.\n",nw);
  348.     while(ct<nw+1)
  349.     {
  350.         Verbs[ct]=ReadString(f);
  351.         Nouns[ct]=ReadString(f);
  352.         ct++;
  353.     }
  354.     ct=0;
  355.     rp=Rooms;
  356.     if(loud)
  357.         printf("Reading %d rooms.\n",nr);
  358.     while(ct<nr+1)
  359.     {
  360.         fscanf(f,"%hd %hd %hd %hd %hd %hd",
  361.             &rp->Exits[0],&rp->Exits[1],&rp->Exits[2],
  362.             &rp->Exits[3],&rp->Exits[4],&rp->Exits[5]);
  363.         rp->Text=ReadString(f);
  364.         ct++;
  365.         rp++;
  366.     }
  367.     ct=0;
  368.     if(loud)
  369.         printf("Reading %d messages.\n",mn);
  370.     while(ct<mn+1)
  371.     {
  372.         Messages[ct]=ReadString(f);
  373.         ct++;
  374.     }
  375.     ct=0;
  376.     if(loud)
  377.         printf("Reading %d items.\n",ni);
  378.     ip=Items;
  379.     while(ct<ni+1)
  380.     {
  381.         ip->Text=ReadString(f);
  382.         ip->AutoGet=strchr(ip->Text,'/');
  383.         /* Some games use // to mean no auto get/drop word! */
  384.         if(ip->AutoGet && strcmp(ip->AutoGet,"//") && strcmp(ip->AutoGet,"/*"))
  385.         {
  386.             char *t;
  387.             *ip->AutoGet++=0;
  388.             t=strchr(ip->AutoGet,'/');
  389.             if(t!=NULL)
  390.                 *t=0;
  391.         }
  392.         fscanf(f,"%hd",&lo);
  393.         ip->Location=(unsigned char)lo;
  394.         ip->InitialLoc=ip->Location;
  395.         ip++;
  396.         ct++;
  397.     }
  398.     ct=0;
  399.     /* Discard Comment Strings */
  400.     while(ct<na+1)
  401.     {
  402.         free(ReadString(f));
  403.         ct++;
  404.     }
  405.     fscanf(f,"%d",&ct);
  406.     if(loud)
  407.         printf("Version %d.%02d of Adventure ",
  408.         ct/100,ct%100);
  409.     fscanf(f,"%d",&ct);
  410.     if(loud)
  411.         printf("%d.\nLoad Complete.\n\n",ct);
  412. }
  413.  
  414. int OutputPos=0;
  415.  
  416. void OutReset()
  417. {
  418.     OutputPos=0;
  419.     gotoxy(1,BottomHeight);
  420.     clreol();
  421. }
  422.  
  423. void OutBuf(char *buffer)
  424. {
  425.     char word[80];
  426.     int wp;
  427.  
  428.     while(*buffer)
  429.     {
  430.         if(OutputPos==0)
  431.         {
  432.             while(*buffer && isspace(*buffer))
  433.             {
  434.                 if(*buffer=='\n')
  435.                 {
  436.                     gotoxy(1,BottomHeight);
  437.                     WriteCON("\n");
  438.                     clreol();
  439.                     OutputPos=0;
  440.                 }
  441.                 buffer++;
  442.             }
  443.         }
  444.         if(*buffer==0) {
  445.             return;
  446.         }
  447.         wp=0;
  448.         while(*buffer && !isspace(*buffer))
  449.         {
  450.             word[wp++]=*buffer++;
  451.         }
  452.         word[wp]=0;
  453.         // fprintf(stderr,"Word '%s' at %d\n",word,OutputPos);
  454.         if(OutputPos+strlen(word)>(Width-2))
  455.         {
  456.             gotoxy(1,BottomHeight);
  457.             WriteCON("\n");
  458.             clreol();
  459.             OutputPos=0;
  460.         }
  461.         else
  462.             gotoxy(OutputPos+1,BottomHeight);
  463.         sprintf(str_buf,"%s",word);
  464.         WriteCON(str_buf);
  465.         OutputPos+=strlen(word);
  466.  
  467.         if(*buffer==0) {
  468.             return;
  469.         }
  470.  
  471.         if(*buffer=='\n')
  472.         {
  473.             gotoxy(1,BottomHeight);
  474.             WriteCON("\n");
  475.             clreol();
  476.             OutputPos=0;
  477.         }
  478.         else
  479.         {
  480.             OutputPos++;
  481.             if(OutputPos<(Width-1))
  482.                 WriteCON(" ");
  483.         }
  484.         buffer++;
  485.     }
  486. }
  487.  
  488. void Output(char *a)
  489. {
  490.     char block[512];
  491.     strcpy(block,a);
  492.     OutBuf(block);
  493. }
  494.  
  495. void OutputNumber(int a)
  496. {
  497.     char buf[16];
  498.     sprintf(buf,"%d",a);
  499.     OutBuf(buf);
  500. }
  501.         
  502. void LineInput(char *buf)
  503. {
  504.     int pos=0;
  505.     int ch;
  506.  
  507.     gotoxy(1+OutputPos,BottomHeight);
  508.  
  509.     while(1)
  510.     {
  511.         
  512.         ch = FGetC(CON_handle);
  513.         switch(ch)
  514.         {
  515.             case 10:;
  516.             case 13:;
  517.                 buf[pos]=0;
  518.                 return;
  519.             default:
  520.                 if(ch>=' '&&ch<=126)
  521.                 {
  522.                     buf[pos++]=ch;
  523.                     sprintf(str_buf,"%c",(char)ch);
  524.                     WriteCON(str_buf);
  525.                 }
  526.                 break;
  527.         }
  528.     }
  529. }
  530.  
  531. void GetInput(int *vb, int *no)
  532. {
  533.     char buf[256];
  534.     char verb[10],noun[10];
  535.     int vc,nc;
  536.     int num;
  537.     do
  538.     {
  539.         do
  540.         {
  541.             Output("\nTell me what to do ? ");
  542.             cursor(TRUE);
  543.             LineInput(buf);
  544.             cursor(FALSE);
  545.             OutReset();
  546.             num=sscanf(buf,"%9s %9s",verb,noun);
  547.         }
  548.         while(num==0||*buf=='\n');
  549.         if(num==1)
  550.             *noun=0;
  551.         if(*noun==0 && strlen(verb)==1)
  552.         {
  553.             switch(isupper(*verb)?tolower(*verb):*verb)
  554.             {
  555.                 case 'n':strcpy(verb,"NORTH");break;
  556.                 case 'e':strcpy(verb,"EAST");break;
  557.                 case 's':strcpy(verb,"SOUTH");break;
  558.                 case 'w':strcpy(verb,"WEST");break;
  559.                 case 'u':strcpy(verb,"UP");break;
  560.                 case 'd':strcpy(verb,"DOWN");break;
  561.                 /* Brian Howarth interpreter also supports this */
  562.                 case 'i':strcpy(verb,"INVENTORY");break;
  563.                 /* AMIGA interpreter extension */
  564.                 case 'l':strcpy(verb,"LOOK");break;
  565.             }
  566.         }
  567.         nc=WhichWord(verb,Nouns);
  568.         /* The Scott Adams system has a hack to avoid typing 'go' */
  569.         if(nc>=1 && nc <=6)
  570.         {
  571.             vc=1;
  572.         }
  573.         else
  574.         {
  575.             vc=WhichWord(verb,Verbs);
  576.             nc=WhichWord(noun,Nouns);
  577.         }
  578.         *vb=vc;
  579.         *no=nc;
  580.         if(vc==-1)
  581.         {
  582.             Output("\"");
  583.             Output(verb);
  584.             Output("\" is a word I don't know...sorry!\n");
  585.         }
  586.     }
  587.     while(vc==-1);
  588.     strcpy(NounText,noun);  /* Needed by GET/DROP hack */
  589. }
  590.  
  591. void SaveGame()
  592. {
  593.     char buf[256];
  594.     int ct;
  595.     FILE *f;
  596.  
  597.     Output("Filename: ");
  598.     cursor(TRUE);
  599.     LineInput(buf);
  600.     cursor(FALSE);
  601.     OutReset();
  602.     f=fopen(buf,"w");
  603.     if(f==NULL)
  604.     {
  605.         sprintf(str_buf,"Unable to create save file '%s'.\n",buf);
  606.         Output(str_buf);
  607.         return;
  608.     }
  609.     for(ct=0;ct<16;ct++)
  610.     {
  611.         fprintf(f,"%d %d\n",Counters[ct],RoomSaved[ct]);
  612.     }
  613.     fprintf(f,"%ld %d %hd %d %d %hd\n",BitFlags, (BitFlags&(1L<<DARKBIT))?1:0,
  614.         MyLoc,CurrentCounter,SavedRoom,GameHeader.LightTime);
  615.     for(ct=0;ct<=GameHeader.NumItems;ct++)
  616.         fprintf(f,"%hd\n",(short)Items[ct].Location);
  617.     fclose(f);
  618.     sprintf(str_buf,"Saved '%s'.\n",buf);
  619.     Output(str_buf);
  620. }
  621.  
  622. BOOL LoadGame(char *name)
  623. {
  624.     FILE *f=fopen(name,"r");
  625.     int ct=0;
  626.     short lo;
  627.     short DarkFlag;
  628.  
  629.     if(f==NULL)
  630.     {
  631.         sprintf(str_buf,"Unable to restore game '%s'.\n",name);
  632.         Output(str_buf);
  633.         return(FALSE);
  634.     }
  635.     for(ct=0;ct<16;ct++)
  636.     {
  637.         fscanf(f,"%d %d\n",&Counters[ct],&RoomSaved[ct]);
  638.     }
  639.     fscanf(f,"%ld %d %hd %d %d %hd\n",
  640.         &BitFlags,&DarkFlag,&MyLoc,&CurrentCounter,&SavedRoom,
  641.         &GameHeader.LightTime);
  642.     /* Backward compatibility */
  643.     if(DarkFlag)
  644.         BitFlags|=(1L<<15);
  645.     for(ct=0;ct<=GameHeader.NumItems;ct++)
  646.     {
  647.         fscanf(f,"%hd\n",&lo);
  648.         Items[ct].Location=(unsigned char)lo;
  649.     }
  650.     fclose(f);
  651.     return(TRUE);
  652. }
  653.  
  654. void RestoreGame()
  655. {
  656.     char buf[256];
  657.  
  658.     Output("Filename: ");
  659.     cursor(TRUE);
  660.     LineInput(buf);
  661.     OutReset();
  662.     cursor(FALSE);
  663.     if (LoadGame(buf)) {
  664.         sprintf(str_buf,"Restored '%s'.\n",buf);
  665.         Output(str_buf);
  666.     }
  667. }
  668.  
  669. int WhichWord(char *word, char **list)
  670. {
  671.     int n=1;
  672.     int ne=1;
  673.     char *tp;
  674.  
  675.     /* quick & dirty workaround for missing feature 'RESTORE'
  676.        no more need for quit/restart game. */
  677.     if(strnicmp(word,"!RESTORE",GameHeader.WordLength)==0) {
  678.         RestoreGame();
  679.         strcpy(word,"LOOK");
  680.     }
  681.  
  682.     while(ne<=GameHeader.NumWords)
  683.     {
  684.         tp=list[ne];
  685.         if(*tp=='*')
  686.             tp++;
  687.         else
  688.             n=ne;
  689.         if(strnicmp(word,tp,GameHeader.WordLength)==0)
  690.             return(n);
  691.         ne++;
  692.     }
  693.     return(-1);
  694. }
  695.  
  696. int PerformLine(int ct)
  697. {
  698.     int continuation=0;
  699.     int param[5],pptr=0;
  700.     int act[4];
  701.     int cc=0;
  702.     while(cc<5)
  703.     {
  704.         int cv,dv;
  705.         cv=Actions[ct].Condition[cc];
  706.         dv=cv/20;
  707.         cv=cv%20;
  708.         //cv%=20;
  709.         switch(cv)
  710.         {
  711.             case 0:
  712.                 param[pptr++]=dv;
  713.                 break;
  714.             case 1:
  715.                 if(Items[dv].Location!=CARRIED)
  716.                     return(0);
  717.                 break;
  718.             case 2:
  719.                 if(Items[dv].Location!=MyLoc)
  720.                     return(0);
  721.                 break;
  722.             case 3:
  723.                 if(Items[dv].Location!=CARRIED&&
  724.                     Items[dv].Location!=MyLoc)
  725.                     return(0);
  726.                 break;
  727.             case 4:
  728.                 if(MyLoc!=dv)
  729.                     return(0);
  730.                 break;
  731.             case 5:
  732.                 if(Items[dv].Location==MyLoc)
  733.                     return(0);
  734.                 break;
  735.             case 6:
  736.                 if(Items[dv].Location==CARRIED)
  737.                     return(0);
  738.                 break;
  739.             case 7:
  740.                 if(MyLoc==dv)
  741.                     return(0);
  742.                 break;
  743.             case 8:
  744.                 if((BitFlags&(1L<<dv))==0)
  745.                     return(0);
  746.                 break;
  747.             case 9:
  748.                 if(BitFlags&(1L<<dv))
  749.                     return(0);
  750.                 break;
  751.             case 10:
  752.                 if(CountCarried()==0)
  753.                     return(0);
  754.                 break;
  755.             case 11:
  756.                 if(CountCarried())
  757.                     return(0);
  758.                 break;
  759.             case 12:
  760.                 if(Items[dv].Location==CARRIED||Items[dv].Location==MyLoc)
  761.                     return(0);
  762.                 break;
  763.             case 13:
  764.                 if(Items[dv].Location==0)
  765.                     return(0);
  766.                 break;
  767.             case 14:
  768.                 if(Items[dv].Location)
  769.                     return(0);
  770.                 break;
  771.             case 15:
  772.                 if(CurrentCounter>dv)
  773.                     return(0);
  774.                 break;
  775.             case 16:
  776.                 if(CurrentCounter<=dv)
  777.                     return(0);
  778.                 break;
  779.             case 17:
  780.                 if(Items[dv].Location!=Items[dv].InitialLoc)
  781.                     return(0);
  782.                 break;
  783.             case 18:
  784.                 if(Items[dv].Location==Items[dv].InitialLoc)
  785.                     return(0);
  786.                 break;
  787.             case 19: /* Only seen in Brian Howarth games so far */
  788.                 if(CurrentCounter!=dv)
  789.                     return(0);
  790.                 break;
  791.         }
  792.         cc++;
  793.     }
  794.     /* Actions */
  795.     act[0]=Actions[ct].Action[0];
  796.     act[2]=Actions[ct].Action[1];
  797.     act[1]=act[0]%150;
  798.     act[3]=act[2]%150;
  799.     act[0]/=150;
  800.     act[2]/=150;
  801.     cc=0;
  802.     pptr=0;
  803.     while(cc<4)
  804.     {
  805.         if(act[cc]>=1 && act[cc]<52)
  806.         {
  807.             Output(Messages[act[cc]]);
  808.             Output("\n");
  809.         }
  810.         else if(act[cc]>101)
  811.         {
  812.             Output(Messages[act[cc]-50]);
  813.             Output("\n");
  814.         }
  815.         else switch(act[cc])
  816.         {
  817.             case 0: /* NOP */
  818.                 break;
  819.             case 52:
  820.                 if(CountCarried()==GameHeader.MaxCarry)
  821.                 {
  822.                     if(Options&YOUARE)
  823.                         Output("You are carrying too much.\n");
  824.                     else
  825.                         Output("I've too much to carry!\n");
  826.                     break;
  827.                 }
  828.                 if(Items[param[pptr]].Location==MyLoc)
  829.                     Redraw=1;
  830.                 Items[param[pptr++]].Location= CARRIED;
  831.                 break;
  832.             case 53:
  833.                 Redraw=1;
  834.                 Items[param[pptr++]].Location=MyLoc;
  835.                 break;
  836.             case 54:
  837.                 Redraw=1;
  838.                 MyLoc=param[pptr++];
  839.                 break;
  840.             case 55:
  841.                 if(Items[param[pptr]].Location==MyLoc)
  842.                     Redraw=1;
  843.                 Items[param[pptr++]].Location=0;
  844.                 break;
  845.             case 56:
  846.                 BitFlags|=1L<<DARKBIT;
  847.                 break;
  848.             case 57:
  849.                 BitFlags&=~(1L<<DARKBIT);
  850.                 break;
  851.             case 58:
  852.                 BitFlags|=(1L<<param[pptr++]);
  853.                 break;
  854.             case 59:
  855.                 if(Items[param[pptr]].Location==MyLoc)
  856.                     Redraw=1;
  857.                 Items[param[pptr++]].Location=0;
  858.                 break;
  859.             case 60:
  860.                 BitFlags&=~(1L<<param[pptr++]);
  861.                 break;
  862.             case 61:
  863.                 if(Options&YOUARE)
  864.                     Output("You are dead.\n");
  865.                 else
  866.                     Output("I am dead.\n");
  867.                 BitFlags&=~(1L<<DARKBIT);
  868.                 MyLoc=GameHeader.NumRooms; /* It seems to be what the code says! */
  869.                 Look();
  870.                 break;
  871.             case 62:
  872.             {
  873.                 /* Bug fix for some systems - before it could get parameters wrong */
  874.                 int i=param[pptr++];
  875.                 Items[i].Location=param[pptr++];
  876.                 Redraw=1;
  877.                 break;
  878.             }
  879.             case 63:
  880. doneit:         Fatal("The game is now over");
  881.                 Delay(250);
  882.                 close_all();
  883.                 exit(0);
  884.             case 64:
  885.                 Look();
  886.                 break;
  887.             case 65:
  888.             {
  889.                 int ct=0;
  890.                 int n=0;
  891.                 while(ct<=GameHeader.NumItems)
  892.                 {
  893.                     if(Items[ct].Location==GameHeader.TreasureRoom &&
  894.                       *Items[ct].Text=='*')
  895.                         n++;
  896.                     ct++;
  897.                 }
  898.                 if(Options&YOUARE)
  899.                     Output("You have stored ");
  900.                 else
  901.                     Output("I've stored ");
  902.                 OutputNumber(n);
  903.                 Output(" treasures.  On a scale of 0 to 100, that rates ");
  904.                 OutputNumber((n*100)/GameHeader.Treasures);
  905.                 Output(".\n");
  906.                 if(n==GameHeader.Treasures)
  907.                 {
  908.                     Output("Well done.\n");
  909.                     goto doneit;
  910.                 }
  911.                 break;
  912.             }
  913.             case 66:
  914.             {
  915.                 int ct=0;
  916.                 int f=0;
  917.                 if(Options&YOUARE)
  918.                     Output("You are carrying:\n");
  919.                 else
  920.                     Output("I'm carrying:\n");
  921.                 while(ct<=GameHeader.NumItems)
  922.                 {
  923.                     if(Items[ct].Location==CARRIED)
  924.                     {
  925.                         if(f==1)
  926.                         {
  927.                             if (Options & TRS80_STYLE)
  928.                                 Output(". ");
  929.                             else
  930.                                 Output(" - ");
  931.                         }
  932.                         f=1;
  933.                         Output(Items[ct].Text);
  934.                     }
  935.                     ct++;
  936.                 }
  937.                 if(f==0)
  938.                     Output("Nothing");
  939.                 Output(".\n");
  940.                 break;
  941.             }
  942.             case 67:
  943.                 BitFlags|=(1L<<0);
  944.                 break;
  945.             case 68:
  946.                 BitFlags&=~(1L<<0);
  947.                 break;
  948.             case 69:
  949.                 GameHeader.LightTime=LightRefill;
  950.                 if(Items[LIGHT_SOURCE].Location==MyLoc)
  951.                     Redraw=1;
  952.                 Items[LIGHT_SOURCE].Location=CARRIED;
  953.                 BitFlags&=~(1L<<LIGHTOUTBIT);
  954.                 break;
  955.             case 70:
  956.                 ClearScreen(); /* pdd. */
  957.                 OutReset();
  958.                 break;
  959.             case 71:
  960.                 SaveGame();
  961.                 break;
  962.             case 72:
  963.             {
  964.                 int i1=param[pptr++];
  965.                 int i2=param[pptr++];
  966.                 int t=Items[i1].Location;
  967.                 if(t==MyLoc || Items[i2].Location==MyLoc)
  968.                     Redraw=1;
  969.                 Items[i1].Location=Items[i2].Location;
  970.                 Items[i2].Location=t;
  971.                 break;
  972.             }
  973.             case 73:
  974.                 continuation=1;
  975.                 break;
  976.             case 74:
  977.                 if(Items[param[pptr]].Location==MyLoc)
  978.                     Redraw=1;
  979.                 Items[param[pptr++]].Location= CARRIED;
  980.                 break;
  981.             case 75:
  982.             {
  983.                 int i1,i2;
  984.                 i1=param[pptr++];
  985.                 i2=param[pptr++];
  986.                 if(Items[i1].Location==MyLoc)
  987.                     Redraw=1;
  988.                 Items[i1].Location=Items[i2].Location;
  989.                 if(Items[i2].Location==MyLoc)
  990.                     Redraw=1;
  991.                 break;
  992.             }
  993.             case 76:    /* Looking at adventure .. */
  994.                 Look();
  995.                 break;
  996.             case 77:
  997.                 if(CurrentCounter>=0)
  998.                     CurrentCounter--;
  999.                 break;
  1000.             case 78:
  1001.                 OutputNumber(CurrentCounter);
  1002.                 break;
  1003.             case 79:
  1004.                 CurrentCounter=param[pptr++];
  1005.                 break;
  1006.             case 80:
  1007.             {
  1008.                 int t=MyLoc;
  1009.                 MyLoc=SavedRoom;
  1010.                 SavedRoom=t;
  1011.                 Redraw=1;
  1012.                 break;
  1013.             }
  1014.             case 81:
  1015.             {
  1016.                 /* This is somewhat guessed. Claymorgue always
  1017.                    seems to do select counter n, thing, select counter n,
  1018.                    but uses one value that always seems to exist. Trying
  1019.                    a few options I found this gave sane results on ageing */
  1020.                 int t=param[pptr++];
  1021.                 int c1=CurrentCounter;
  1022.                 CurrentCounter=Counters[t];
  1023.                 Counters[t]=c1;
  1024.                 break;
  1025.             }
  1026.             case 82:
  1027.                 CurrentCounter+=param[pptr++];
  1028.                 break;
  1029.             case 83:
  1030.                 CurrentCounter-=param[pptr++];
  1031.                 if(CurrentCounter< -1)
  1032.                     CurrentCounter= -1;
  1033.                 /* Note: This seems to be needed. I don't yet
  1034.                    know if there is a maximum value to limit too */
  1035.                 break;
  1036.             case 84:
  1037.                 Output(NounText);
  1038.                 break;
  1039.             case 85:
  1040.                 Output(NounText);
  1041.                 Output("\n");
  1042.                 break;
  1043.             case 86:
  1044.                 Output("\n");
  1045.                 break;
  1046.             case 87:
  1047.             {
  1048.                 /* Changed this to swap location<->roomflag[x]
  1049.                    not roomflag 0 and x */
  1050.                 int p=param[pptr++];
  1051.                 int sr=MyLoc;
  1052.                 MyLoc=RoomSaved[p];
  1053.                 RoomSaved[p]=sr;
  1054.                 Redraw=1;
  1055.                 break;
  1056.             }
  1057.             case 88:
  1058.                 Delay(100); /* DOC's say 2 seconds. Spectrum times at 1.5 */
  1059.                 break;
  1060.             case 89:
  1061.                 pptr++;
  1062.                 /* SAGA draw picture n */
  1063.                 /* Spectrum Seas of Blood - start combat ? */
  1064.                 /* Poking this into older spectrum games causes a crash */
  1065.                 break;
  1066.             default:
  1067.                 fprintf(stderr,"Unknown action %d [Param begins %d %d]\n",
  1068.                     act[cc],param[pptr],param[pptr+1]);
  1069.                 break;
  1070.         }
  1071.         cc++;
  1072.     }
  1073.     return(1+continuation);
  1074. }
  1075.  
  1076.  
  1077. int PerformActions(int vb,int no)
  1078. {
  1079.     static int disable_sysfunc=0;   /* Recursion lock */
  1080.     int d=BitFlags&(1L<<DARKBIT);
  1081.     
  1082.     int ct=0;
  1083.     int fl;
  1084.     int doagain=0;
  1085.     if(vb==1 && no == -1 )
  1086.     {
  1087.         Output("Give me a direction too.\n");
  1088.         return(0);
  1089.     }
  1090.     if(vb==1 && no>=1 && no<=6)
  1091.     {
  1092.         int nl;
  1093.         if(Items[LIGHT_SOURCE].Location==MyLoc ||
  1094.            Items[LIGHT_SOURCE].Location==CARRIED)
  1095.             d=0;
  1096.         if(d)
  1097.             Output("Dangerous to move in the dark!\n");
  1098.         nl=Rooms[MyLoc].Exits[no-1];
  1099.         if(nl!=0)
  1100.         {
  1101.             MyLoc=nl;
  1102.             Output("O.K.\n");
  1103.             Look();
  1104.             return(0);
  1105.         }
  1106.         if(d)
  1107.         {
  1108.             if(Options&YOUARE)
  1109.                 Output("You fell down and broke your neck.\n");
  1110.             else
  1111.                 Output("I fell down and broke my neck.\n");
  1112.             Delay(250);
  1113.             close_all();
  1114.             exit(0);
  1115.         }
  1116.         if(Options&YOUARE)
  1117.             Output("You can't go in that direction.\n");
  1118.         else
  1119.             Output("I can't go in that direction.\n");
  1120.         return(0);
  1121.     }
  1122.     fl= -1;
  1123.     while(ct<=GameHeader.NumActions)
  1124.     {
  1125.         int vv,nv;
  1126.         vv=Actions[ct].Vocab;
  1127.         /* Think this is now right. If a line we run has an action73
  1128.            run all following lines with vocab of 0,0 */
  1129.         if(vb!=0 && (doagain&&vv!=0))
  1130.             break;
  1131.         /* Oops.. added this minor cockup fix 1.11 */
  1132.         if(vb!=0 && !doagain && fl== 0)
  1133.             break;
  1134.         nv=vv%150;
  1135.         vv/=150;
  1136.         if((vv==vb)||(doagain&&Actions[ct].Vocab==0))
  1137.         {
  1138.             if((vv==0 && RandomPercent(nv))||doagain||
  1139.                 (vv!=0 && (nv==no||nv==0)))
  1140.             {
  1141.                 int f2;
  1142.                 if(fl== -1)
  1143.                     fl= -2;
  1144.                 if((f2=PerformLine(ct))>0)
  1145.                 {
  1146.                     /* ahah finally figured it out ! */
  1147.                     fl=0;
  1148.                     if(f2==2)
  1149.                         doagain=1;
  1150.                     if(vb!=0 && doagain==0)
  1151.                         return(0);
  1152.                 }
  1153.             }
  1154.         }
  1155.         ct++;
  1156.         if(Actions[ct].Vocab!=0)
  1157.             doagain=0;
  1158.     }
  1159.     if(fl!=0 && disable_sysfunc==0)
  1160.     {
  1161.         int i;
  1162.         if(Items[LIGHT_SOURCE].Location==MyLoc ||
  1163.            Items[LIGHT_SOURCE].Location==CARRIED)
  1164.             d=0;
  1165.         if(vb==10 || vb==18)
  1166.         {
  1167.             /* Yes they really _are_ hardcoded values */
  1168.             if(vb==10)
  1169.             {
  1170.                 if(stricmp(NounText,"ALL")==0)
  1171.                 {
  1172.                     int ct=0;
  1173.                     int f=0;
  1174.                     
  1175.                     if(d)
  1176.                     {
  1177.                         Output("It is dark.\n");
  1178.                         return 0;
  1179.                     }
  1180.                     while(ct<=GameHeader.NumItems)
  1181.                     {
  1182.                         if(Items[ct].Location==MyLoc && Items[ct].AutoGet!=NULL && Items[ct].AutoGet[0]!='*')
  1183.                         {
  1184.                             no=WhichWord(Items[ct].AutoGet,Nouns);
  1185.                             disable_sysfunc=1;  /* Don't recurse into auto get ! */
  1186.                             PerformActions(vb,no);  /* Recursively check each items table code */
  1187.                             disable_sysfunc=0;
  1188.                             if(CountCarried()==GameHeader.MaxCarry)
  1189.                             {
  1190.                                 if(Options&YOUARE)
  1191.                                     Output("You are carrying too much.\n");
  1192.                                 else
  1193.                                     Output("I've too much to carry.\n");
  1194.                                 return(0);
  1195.                             }
  1196.                             Items[ct].Location= CARRIED;
  1197.                             Redraw=1;
  1198.                             OutBuf(Items[ct].Text);
  1199.                             Output(": O.K.\n");
  1200.                             f=1;
  1201.                         }
  1202.                         ct++;
  1203.                     }
  1204.                     if(f==0)
  1205.                         Output("Nothing taken.\n");
  1206.                     return(0);
  1207.                 }
  1208.                 if(no==-1)
  1209.                 {
  1210.                     Output("What ?\n");
  1211.                     return(0);
  1212.                 }
  1213.                 if(CountCarried()==GameHeader.MaxCarry)
  1214.                 {
  1215.                     if(Options&YOUARE)
  1216.                         Output("You are carrying too much.\n");
  1217.                     else
  1218.                         Output("I've too much to carry.\n");
  1219.                     return(0);
  1220.                 }
  1221.                 i=MatchUpItem(NounText,MyLoc);
  1222.                 if(i==-1)
  1223.                 {
  1224.                     if(Options&YOUARE)
  1225.                         Output("It is beyond your power to do that.\n");
  1226.                     else
  1227.                         Output("It's beyond my power to do that.\n");
  1228.                     return(0);
  1229.                 }
  1230.                 Items[i].Location= CARRIED;
  1231.                 Output("O.K.\n");
  1232.                 Redraw=1;
  1233.                 return(0);
  1234.             }
  1235.             if(vb==18)
  1236.             {
  1237.                 if(stricmp(NounText,"ALL")==0)
  1238.                 {
  1239.                     int ct=0;
  1240.                     int f=0;
  1241.                     while(ct<=GameHeader.NumItems)
  1242.                     {
  1243.                         if(Items[ct].Location==CARRIED && Items[ct].AutoGet && Items[ct].AutoGet[0]!='*')
  1244.                         {
  1245.                             no=WhichWord(Items[ct].AutoGet,Nouns);
  1246.                             disable_sysfunc=1;
  1247.                             PerformActions(vb,no);
  1248.                             disable_sysfunc=0;
  1249.                             Items[ct].Location=MyLoc;
  1250.                             OutBuf(Items[ct].Text);
  1251.                             Output(": O.K.\n");
  1252.                             Redraw=1;
  1253.                             f=1;
  1254.                         }
  1255.                         ct++;
  1256.                     }
  1257.                     if(f==0)
  1258.                         Output("Nothing dropped.\n");
  1259.                     return(0);
  1260.                 }
  1261.                 if(no==-1)
  1262.                 {
  1263.                     Output("What ?\n");
  1264.                     return(0);
  1265.                 }
  1266.                 i=MatchUpItem(NounText,CARRIED);
  1267.                 if(i==-1)
  1268.                 {
  1269.                     if(Options&YOUARE)
  1270.                         Output("It's beyond your power to do that.\n");
  1271.                     else
  1272.                         Output("It's beyond my power to do that.\n");
  1273.                     return(0);
  1274.                 }
  1275.                 Items[i].Location=MyLoc;
  1276.                 Output("O.K.\n");
  1277.                 Redraw=1;
  1278.                 return(0);
  1279.             }
  1280.         }
  1281.     }
  1282.     return(fl);
  1283. }
  1284.     
  1285. void main(int argc, char *argv[])
  1286. {
  1287.     FILE *f;
  1288.     int vb,no;
  1289.  
  1290.     while(argv[1])
  1291.     {
  1292.         if(*argv[1]!='-')
  1293.             break;
  1294.         switch(argv[1][1])
  1295.         {
  1296.             case 'y':
  1297.                 Options|=YOUARE;
  1298.                 break;
  1299.             case 'i':
  1300.                 Options&=~YOUARE;
  1301.                 break;
  1302.             case 'd':
  1303.                 Options|=DEBUGGING;
  1304.                 break;
  1305.             case 's':
  1306.                 Options|=SCOTTLIGHT;
  1307.                 break;
  1308.             case 't':
  1309.                 Options|=TRS80_STYLE;
  1310.                 break;
  1311.             case 'p':
  1312.                 Options|=PREHISTORIC_LAMP;
  1313.                 break;
  1314.             case 'h':
  1315.             default:
  1316.                 fprintf(stderr,"%s: [-h] [-y] [-s] [-i] [-t] [-d] [-p] <gamename> [savedgame].\n",
  1317.                         argv[0]);
  1318.                 exit(1);
  1319.         }
  1320.         if(argv[1][2]!=0)
  1321.         {
  1322.             fprintf(stderr,"%s: option -%c does not take a parameter.\n",
  1323.                 argv[0],argv[1][1]);
  1324.             exit(1);
  1325.         }
  1326.         argv++;
  1327.         argc--;
  1328.     }
  1329.  
  1330.     if(argc!=2 && argc!=3)
  1331.     {
  1332.         fprintf(stderr,"%s <database> [<savefile>]\n",argv[0]);
  1333.         exit(1);
  1334.     }
  1335.     f=fopen(argv[1],"r");
  1336.     if(f==NULL)
  1337.     {
  1338.         perror(argv[1]);
  1339.         exit(1);
  1340.     }
  1341.  
  1342.     if (Options & TRS80_STYLE)
  1343.     {
  1344.         Width = 64;
  1345.         TopHeight = 11;
  1346.         BottomHeight = 13;
  1347.     }
  1348.     else
  1349.     {
  1350.         Width = 80;
  1351.         TopHeight = 10;
  1352.         BottomHeight = 15;
  1353.     }
  1354.  
  1355.     AMIGA_init();
  1356.  
  1357.     OutReset();
  1358.     OutBuf("Scott Free, A Scott Adams game driver in C.\n");
  1359.     OutBuf("Release 1.14b, (c) 93-95 Swansea University Computer Society.\n");
  1360.     OutBuf("Distributed under the GNU software license\n");
  1361.     OutBuf("AMIGA V1.0, (c) by Andreas Aumayr (Anden@highnet.co.at)\n\n");
  1362.     OutBuf("Loading adventure data file ...  ");
  1363.     LoadDatabase(f,(Options&DEBUGGING)?1:0);
  1364.     fclose(f);
  1365.     OutBuf("Finished.\n\n");
  1366.     if(argc==3)
  1367.         LoadGame(argv[2]);
  1368.     srand(time(NULL));
  1369.     Look();
  1370.     while(1)
  1371.     {
  1372.         if(Redraw!=0)
  1373.         {
  1374.             Look();
  1375.             Redraw=0;
  1376.         }
  1377.         PerformActions(0,0);
  1378.         if(Redraw!=0)
  1379.         {
  1380.             Look();
  1381.             Redraw=0;
  1382.         }
  1383.         GetInput(&vb,&no);
  1384.         switch(PerformActions(vb,no))
  1385.         {
  1386.             case -1:Output("I don't understand your command.\n");
  1387.                 break;
  1388.             case -2:Output("I can't do that yet.\n");
  1389.                 break;
  1390.         }
  1391.         /* Brian Howarth games seem to use -1 for forever */
  1392.         if(Items[LIGHT_SOURCE].Location/*==-1*/!=DESTROYED && GameHeader.LightTime!= -1)
  1393.         {
  1394.             GameHeader.LightTime--;
  1395.             if(GameHeader.LightTime<1)
  1396.             {
  1397.                 BitFlags|=(1L<<LIGHTOUTBIT);
  1398.                 if(Items[LIGHT_SOURCE].Location==CARRIED ||
  1399.                     Items[LIGHT_SOURCE].Location==MyLoc)
  1400.                 {
  1401.                     if(Options&SCOTTLIGHT)
  1402.                         Output("Light has run out! ");
  1403.                     else
  1404.                         Output("Your light has run out. ");
  1405.                 }
  1406.                 if(Options&PREHISTORIC_LAMP)
  1407.                     Items[LIGHT_SOURCE].Location=DESTROYED;
  1408.             }
  1409.             else if(GameHeader.LightTime<25)
  1410.             {
  1411.                 if(Items[LIGHT_SOURCE].Location==CARRIED ||
  1412.                     Items[LIGHT_SOURCE].Location==MyLoc)
  1413.                 {
  1414.             
  1415.                     if(Options&SCOTTLIGHT)
  1416.                     {
  1417.                         Output("Light runs out in ");
  1418.                         OutputNumber(GameHeader.LightTime);
  1419.                         Output(" turns. ");
  1420.                     }
  1421.                     else
  1422.                     {
  1423.                         if(GameHeader.LightTime%5==0)
  1424.                             Output("Your light is growing dim. ");
  1425.                     }
  1426.                 }
  1427.             }
  1428.         }
  1429.     }
  1430. }
  1431.